import os
import sys
import ctypes
import time


class EChatIMSDKBridge:
    def __init__(self):
        self.dllPath = ""
        self.jsonConfig = ""
        self.handle = None
        self.initFinished = False
        self.callId = 1
        # 使用callbackRefsMap保持python回调函数的引用, 否则可能被python 回收, 导致从动态库回调python异常
        self.callbackRefsMap = {}
        # api 回调方法
        self.apiHandleCallbackMap = {}


    def sdkInitCallback(self, ret, err_msg):
        if ret == 0:
            self.initFinished = True
        else:
            print("sdk init failed, reason = {}".format(err_msg.decode("utf8")))


    def sdkListenerCallback(self, method, argc, argv):
        if method != "" and argc > 0:
            print("sdkListenerCallback: method = {}, argv[0]={}".format(method, argv[0]))



    def sdkApiCallback(self, callId, method, jsonParams):
        methodKey = method.decode('utf-8')
        if self.apiHandleCallbackMap.__contains__(methodKey):
            print("sdkApiCallback: callId = {}, method = {}, argv[0]={}".format(callId, method, jsonParams))
            # 调用回调函数
            cbFunc = self.apiHandleCallbackMap[methodKey]
            cbFunc(jsonParams.decode("utf8"))

    def sdkInit(self, dllPath, jsonConfig):
        self.dllPath = dllPath
        self.jsonConfig = jsonConfig
        if not os.path.isfile(self.dllPath):
            print("dll file not exist.")
            exit(-1)

        if sys.platform == "win32":
            self.handle = ctypes.WinDLL(self.dllPath)
        else:
            self.handle = ctypes.cdll.LoadLibrary(self.dllPath)

        # 定义函数指针签名 typedef void(*pfunc_init_cb)(int ret, const char *err_msg)
        pfuncInitCbType = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
        # 获取绑定python函数的c函数指针
        pfuncInitCb = pfuncInitCbType(self.sdkInitCallback)
        self.callbackRefsMap["pfuncInitCb"] = pfuncInitCb
        # 定义函数指针签名 typedef void(*pfunc_listener_cb)(const char *method, int argc, const char *argv[])
        pfuncListenerCbType = ctypes.CFUNCTYPE(None, ctypes.c_char_p, ctypes.c_int, ctypes.POINTER(ctypes.c_char_p))
        # 获取绑定python函数的c函数指针
        pfuncListenerCb = pfuncListenerCbType(self.sdkListenerCallback)
        self.callbackRefsMap["pfuncListenerCb"] = pfuncListenerCb
        # 定义函数指针签名 typedef void(*pfunc_api_cb)(unsigned long call_id, const char *api_method, const char *response)
        pfuncApiCbType = ctypes.CFUNCTYPE(None, ctypes.c_ulong, ctypes.c_char_p,  ctypes.c_char_p)
        # 获取绑定python函数的c函数指针
        pfuncApiCb = pfuncApiCbType(self.sdkApiCallback)
        self.callbackRefsMap["pfuncApiCb"] = pfuncApiCb
        # 向DLL设置 api 回调函数
        self.handle.sdk_set_api_listener(pfuncApiCb)

        self.handle.sdk_init(jsonConfig.encode('utf-8'), pfuncInitCb, pfuncListenerCb)
        while not self.initFinished:
            time.sleep(1)


    def apiCall(self, method, params, callbackFunc):
        #  register callbackFunc to apiHandleCallbackMap
        self.apiHandleCallbackMap[str(method)] = callbackFunc
        self.handle.sdk_invoke_api(ctypes.c_ulong(self.callId), method.encode('utf-8'), params.encode('utf-8'))
        self.callId += 1


echatimSdk = EChatIMSDKBridge()
